Chapter 14 - Example Programs
WHY THIS CHAPTER?
Although every program in this tutorial has been a complete program, each one has also been a very small program intended to teach you some principle of programming in C. It would do you a disservice to leave you at that point without introducing you to a few larger programs to illustrate how to put together the constructs you have learned to create a major program. This chapter contains four programs of increasing complexity, each designed to take you into a higher plateau of programming, and each designed to be useful to you in some way.
DOSEX will illustrate how to make DOS system calls and will teach you, through self-study, how the system responds to the keyboard. WHATNEXT reads commands input on the command line and will aid you in setting up a variable batch file, one that requests an operator input and responds to the input by branching to a different part of the batch file.
LIST is the source code for the program you used to print out the C source files when you began studying C with the aid of this tutorial. Finally we come to VC, the Visual Calculator, which you should find to be a useful program even if you don't study its source code. VC uses most of the programming techniques we have studied in this course and a few that we never even mentioned such as separately compiled subroutines.
We will take a look at the example programs one at a time but without a complete explanation of any of them because you have been studying C for some time now and should be able to read and understand most of these programs on your own.
The copy of DOS that you received with your IBM-PC or compatible has about 80 internal DOS calls that you can use as a programmer to control your peripheral devices and read information or status from them. Some of the earlier IBM DOS manuals, DOS 2.0 and earlier, have these calls listed in the back of the manual along with how to use them. Most of the manuals supplied with compatible computers make no mention of these calls even though they are extremely useful. These calls can be accessed from nearly any programming language but they do require some initial study to learn how to use them. This program is intended to aid you in this study. Display the program on your monitor or print it out for reference. It is merely a loop watching for a keyboard input or a change in the time. If either happens, it reacts accordingly. In line 32, the function "kbhit()" returns a value of 1 if a key has been hit but not yet read from the input buffer by the program.
Look at the function named "get_time" for an example of a DOS call. An interrupt 21(hex) is called after setting the AH register to 2C(hex) = 44(decimal). The time is returned in the CH, CL, and DH registers. Refer to the DOS call definitions in your copy of DOS. If the definitions are not included there, Peter Nortons book, "Programmers Guide to the IBM PC" is recommended as a good reference manual for these calls and many other programming techniques. Your compiler may have a built in function to do this. If you read your documentation, you will probably find many useful functions available with your compiler that are included as a convenience for you by your compiler writer.
Another useful function is the "pos_cursor()" function that positions the cursor anywhere on the monitor that you desire by using a DOS interrupt. In this case, the interrupt used is 10(hex) which is the general monitor interrupt. This particular service is number 2 of about 10 different monitor services available. This function is included here as another example to you.
The next function, service number 6 of interrupt 10(hex) is the window scroll service. It should be self explanatory.
In this program, the cursor is positioned and some data is output to the monitor, then the cursor is "hidden" by moving it to line 26 which is not displayed. After you compile and run the program, you will notice that the cursor is not visible on the monitor. This is possible in any program, but be sure to put the cursor in view before returning to DOS because DOS does not like to have a "hidden" cursor and may do some strange things.
Some time spent studying this program will be valuable to you as it will reveal how the keyboard data is input to the computer. Especially of importance is how the special keys such as function keys, arrows, etc. are handled. Also note that this program uses full prototype checking and is a good example of how to use it. Since it also uses the "modern" method of function definitions, it is a good example of that also.
This is an example of how to read the data on the command line following the function call. Notice that there are two variables listed within the parentheses following the main() call. The first variable is a count of words in the entire command line including the command itself and the second variable is a pointer to an array of pointers defining the actual words on the command line.
First the question on the command line, made up of some number of words, is displayed on the monitor and the program waits for the operator to hit a key. If the key hit is one of those in the last "word" of the group of words on the command line, the number of the character within the group is returned to the program where it can be tested with the "errorlevel" command in the batch file. You could use this technique to create a variable AUTOEXEC.BAT file or any other batch file can use this for a many way branch. Compile and run this file with TEST.BAT for an example of how it works in practice. You may find this technique useful in one of your batch files and you will almost certainly need to read in the command line parameters someday.
An interesting alternative would be for you to write a program named "WOULD.C" that would return a 1 if a "Y" or "y" were typed and a zero if any other key were hit. Then your batch file could have a line such as;
WOULD YOU LIKE TO USE THE ALTERNATIVE METHOD (Y/N)
Dos would use "WOULD" as the program name, ignore the rest of the statement except for displaying it on the screen. You would then respond to the question on the monitor with a single keyhit. Your batch file would then respond to the 1 or 0 returned and either run the alternative part of the batch file or the primary part whatever each part was.
WOULD YOU LIKE PRIMARY (Y/N) IF ERRORLEVEL 1 GOTO PRIMARY (secondary commands) GOTO DONE :PRIMARY (primary commands) :DONE
This program is actually composed of two files, LIST.C and LISTF.C that must be separately compiled and linked together with your linker. There is nothing new here and you should have no trouble compiling and linking this program by reading the documentation supplied with your C compiler.
The only thing that is new in this program is the inclusion of three "extern" variables in the LISTF.C listing. The only purpose for this is to tie these global variables to the main program and tell the compiler that these are not new variables. The compiler will therefore not generate any new storage space for them but simply use their names during the compile process. At link time, the linker will get their actual storage locations from the LIST.OBJ file and use those locations for the variables in the LISTF part of the memory map also. The variables of those names in both files are therefore the same identical variables and can be used just as any other global variables could be used if both parts of the program were in one file.
There is no reason why the variables couldn't have been defined in the LISTF.C part of the program and declared as "extern" in the LIST.C part. Some of the variables could have been defined in one and some in the other. It is merely a matter of personal taste. Carried to an extreme, all of the variables could have been defined in a third file and named "extern" in both of these files. The third file would then be compiled and included in the linking process.
It would be to your advantage to compile, link, and run this program to prepare you for the next program which is composed of 6 separate files which must all work together.
This program finally ties nearly everything together because it uses nearly every concept covered in the entire tutorial. It is so big that I will not even try to cover the finer points of its operation. Only a few of the more important points will be discussed.
The first thing you should do is go through the tutorial for VC included in the file VC.DOC. There are several dozen steps for you to execute, with each step illustrating some aspect of the Visual Calculator. You will get a good feel for what it is capable of doing and make your study of the source code very profitable. In addition, you will probably find many ways to use the Visual Calculator to solve problems involving calculations where the simplicity of the problem at hand does not warrant writing a program.
Notice that the structure definitions, used in all of the separate parts of the program, are defined in the file STRUCT.DEF. During program development, when it became necessary to change one of the structures slightly, it was not necessary to change it in all of the files, only one file required modification which was then "included" in the source files. Notice that the transcript data is stored in a doubly linked list with the data itself being stored in a separate dynamically allocated char string. This line is pointed to by the pointer "lineloc".
For ease of development, the similar functions were grouped together and compiled separately. Thus, all of the functions involving the monitor were included in the file named VIDEO.C, and all of the functions involving the data storage were grouped into the FILE.C collection. Dividing your program in a way similar to this should simplify debugging and future modifications.
Of special interest is the "monitor()" function. This function examines the video mode through use of a DOS command and if it is a 7, it assumes it is a monochrome monitor, otherwise it assumes a color monitor. The colors of the various fields are established at this time and used throughout the program. Most of the data is written directly to the video memory, but some is written through the standard BIOS routines.
The file DEFIN.H is a catalogue of the functions to aid in finding the functions. This file was generated as one of the first files and was maintained and updated for use during the entire design and coding lifetime. It also contains all of the prototype definitions for the functions in all of the source files, and is "included" in every source file to do prototype checking.
/* VC.C VC.C VC.C VC.C VC.C VC.C VC.C VISUAL CALCULATOR X X XXX MAIN PROGRAM X X X X X X X July 1, 1987 X X X X X X X X X X XXX This program will evaluate single value expressions in a manner similar to those evaluated by a hand-held calculator, hence its name, the Visual Calculator. It was never intended to be programmable, so no loop constructs are included in its design. It is possible to write a series of statements, store them in a file, and recall them while using them to calculate with new values of input variables in the six variable storage registers. The input variables can be changed, and the entire series recalculated. Although this is a potentially useful program in its own right, it was originally written as an illustration of a rather large C program. It is especially useful because the student of C can run the program to determine its operating characteristics, then study the code needed to perform the various operations. For that reason, the entire program is heavily commented. An actual production program would probably not have as many comments as this example but it would not be bad practice to comment all of your programs to this extent. */ #include "ctype.h" #include "stdio.h" #include "string.h" #include "conio.h" #include "process.h" #include "struct.def" #include "defin.h" struct vars allvars[12]; /* this is the main variable storage */ int varinuse = 0; /* which variable is being used now */ char inline[200]; /* input line area */ int col; /* used for searching across the input */ int errcode; /* error code number */ int colerr; /* column where error occurred */ int printit = 0; /* 1 = print a transcript */ int ignore; /* 1 = ignore calculations for line */ extern char strngout[]; /* output message area */ extern int valattr; /* value and variable attribute */ extern int helpattr; /* help box attribute */ FILE *prtfile; /* file pointers */ struct lines *top, *bot, *q, *p, *arrow, *trnsend; /* *********************************************************** main */ /* This is the main control loop for the program. It initializes */ /* everything and reads statements until no errors are found. It */ /* continues reading until an F10 is detected in a subordinate */ /* function where control is returned to DOS */ main() { top = bot = q = p = arrow = trnsend = NULL; monitor(); /* initialize video attributes */ initdata(&allvars[0]); /* initialize all data */ bkgndvid(); /* display video background - double lines */ valusvid(); /* display starting values of all variables */ strtrans("Welcome to the Visual Calculator - Version 1.10",0); transout(); do{ poscurs(23,7); printf(" input > "); printf(" "); do { /* repeat input until no errors */ readline(); /* get an input line */ errdis(" "); /* clear error msg */ parse(); /* parse the line */ if (errcode) errout();/* output error message */ } while (errcode); if (ignore == 1) strtrans(inline,0); /* store comment in transcript */ else strtrans(inline,1); /* store "inline" in transcript */ transout(); } while (1); /* continuous loop */ } /* ******************************************************* readline */ /* This function reads a line by inputting one character at a time */ /* and deciding what to do with it if it is a special character, or */ /* adding it to the input line if it is a special character. The */ /* routine takes care of such things as backspace, cursor movement */ /* and delete keys. The final result is a single line of text stored*/ /* in the buffer "inline" and the line displayed on the monitor. */ void readline(void) { int index; int c,temp; int row = 23,col = 17; int attr; if (errcode) { /* error recovery allow reenter */ index = colerr; errcode = 0; } else { /* normal input routine */ index = 0; for (temp = 0;temp < 80;temp++) inline[temp] = 0; /* clear input buffer */ } poscurs(row,col+index); /* starting location of cursor */ do { /* repeat this do loop until a return is hit */ while ((c = getch()) == EOF); /* get a keystroke */ if (c == 0) { /* a zero here says a special key was hit */ /* get the key and act on it as needed */ int spec; spec = getch(); /* this is the special code found */ switch (spec) { case 59 : helpm(); /* F1 - Help math */ transout(); break; case 60 : helps(); /* F2 - Help system */ transout(); break; case 61 : if (printit) { /* F3 - Print on/off */ printit = 0; /* print off */ fprintf(prtfile,"%s\n\n","Print off"); fclose(prtfile); strcpy(strngout,"-----"); attr = helpattr; } else { prtfile = fopen("PRN","w"); /* print on */ if (prtprblm()) { errcode = 12; /* printer is not ready */ errout(); break; } printit = 1; fprintf(prtfile,"%s\n","Print On"); strcpy(strngout,"Print"); attr = valattr; } strngdis(1,73,attr); break; case 62 : /* F4 - Mark transcript */ arrow->marked = (arrow->marked?0:1); transout(); break; case 63 : fileout(); /* F5 - Store transcript */ break; case 64 : filein(); /* F6 - Retrieve trans */ errcode = 0; break; case 65 : /* F7 - */ break; case 66 : /* F8 - */ break; case 67 : /* F9 - Edit a line */ strcpy(inline,arrow->lineloc); poscurs(23,17); printf("%s",inline); break; case 68 : poscurs(23,17); /* F10 - Quit to DOS */ printf("Quit? (Y/N) "); c = getch(); if ((c == 'Y') || (c == 'y')){ clrscrn(); exit(0); } poscurs(23,17); printf(" "); break; case 75 : if (index) { /* left arrow */ index = index -1; /* back up cursor */ } break; case 77 : if (index < 65) { /* right arrow */ if (inline[index] == 0) /* zero found */ inline[index] = ' '; /* blank over 0 */ index = index + 1; /* cursor forward */ } break; case 72 : movarrow(-1); /* up arrow */ break; case 80 : movarrow(1); /* down arrow */ break; case 73 : movarrow(-8); /* page up */ break; case 81 : movarrow(8); /* page down */ break; case 71 : movarrow(-1000); /* home */ break; case 79 : movarrow(1000); /* end */ break; case 83 : temp = index; /* delete key */ /* move all characters left one space */ while (inline[temp]) { inline[temp] = inline[temp+1]; putchar(inline[temp++]); } putchar(0); /* zero in last place */ break; default : poscurs(15,5); printf(" S%3d",spec); } poscurs(row,col+index); /* actually put cursor in position */ } else { /* normal letter or char hit */ int curr,next; if (islower(c)) c = toupper(c); /* convert to upper case */ if ((c >= '\40') && (c <= '\176')) { /* printable char */ poscurs(row,col+index); putchar(c); next = inline[index]; inline[index++] = c; curr = index; while((next != 0) && (curr <= 65)) { /* move remainder */ temp = next; /* line right */ next = inline[curr]; inline[curr++] = temp; putchar(temp); } } else { if ((c == 8) && index){ /* backspace */ index--; poscurs(row,col+index); /* back up cursor */ temp = index; while (inline[temp]) { inline[temp] = inline[temp+1]; putchar(inline[temp++]); } putchar(0); } } poscurs(row,col+index); } if (c == 3) exit(0); /* ctrl-break, out to DOS */ } while (c != 13); /* newline found, line input is complete */ } /* ********************************************************** parse */ /* This function does a lot of checking of the input line for */ /* logical errors in construction, then turns control over to the */ /* function "calcdata" for the actual calculations. */ void parse(void) { int index,parcol; double newval; char name[7]; varinuse = -1; errcode = 0; col = 0; ignore = 1; /* ignore this line */ if (inline[0] == '#') { /* get list of variable names */ getnames(); return; } while (inline[col] == ' ') col++; /* ignore leading blanks */ if (inline[col] == '$') return; /* ignore a comment line */ if (inline[col] == 0) return; /* ignore a blank line */ ignore = 0; /* don't ignore this line */ name[0] = inline[col++]; /* find variable name */ index = 1; while ((((inline[col] >= 'A') && (inline[col] <= 'Z')) || ((inline[col] >= '0') && (inline[col] <= '9'))) && (index <= 5)) { /* continue var or function name */ name[index++] = inline[col++]; } name[index] = 0; /* name found */ for (index = 0;index < 12;index++) { if ((strcmp(name,allvars[index].varname)) == 0) varinuse = index; /* variable name found */ } if (varinuse < 0) errchk(3); /* unknown variable name */ while (inline[col] == ' ') col++; /* ignore leading blanks */ if (inline[col] == '=') col++; else errchk(8); /* missing equal sign */ parcol = 0; /* now check for correct parenthesis matchup */ index = col; do { if (inline[col] == '(') parcol++; if (inline[col++] == ')') parcol--; if (parcol < 0) errchk(1); /* paren count went negative */ } while (inline[col]); if (parcol) errchk(2); /* left over parentheses */ col = index; calcdata(&newval); /* now go evaluate the full expression */ if (errcode == 0) { /* don't update value if error found */ allvars[varinuse].value = newval; disnew(varinuse); /* display the changed value */ } } /* ********************************************************* errout */ /* This is the function that displays the blinking error message on */ /* the monitor. Note the extra errors for expansion of the table. */ void errout(void) { switch (errcode) { case 1 : errdis("extra right parentheses "); break; case 2 : errdis("missing right parentheses"); break; case 3 : errdis("unknown variable name "); break; case 4 : errdis("invalid math operator "); break; case 5 : errdis("negative value for SQRT "); break; case 6 : errdis("function not found "); break; case 7 : errdis("negative value for LOG "); break; case 8 : errdis("equal sign missing "); break; case 9 : errdis("invalid data field "); break; case 10 : errdis("division by zero "); break; case 11 : errdis("File doesn't exist "); break; case 12 : errdis("Printer not ready "); break; case 13 : errdis("Out of memory "); break; case 14 : errdis("Dash expected "); break; case 15 : errdis("Invalid format code "); break; case 16 : errdis("Neg value for FACTORIAL "); break; case 17 : errdis("Err 17 "); break; default : errdis("unknown error "); poscurs(21,70); printf("%d",errcode); } poscurs(23,12+colerr); }
The Visual Calculator - Version 1.10 The visual calculator was written to be used for quick calculations of the variety that would ordinarily be done with a hand held calculator. There is no allowance for programming loops, or indirect variables, or any of the other facilities of a modern programming language. There are no complications either, and this program should not require more than a few minutes for the experienced com- puter user to learn to use, and only slightly longer for the person inexperienced with computers. It is suggested that you slowly run through the tutor- ial first, performing the operations suggested, then read the following comments for a description of the visual calculator. This program is intended to be much more comp- rehensive than the little on-screen calculators that have become popular, but it is not memory resident. Due to the expected future popularity of such programs as "Windows", this program can be as convenient as the present memory resident programs. The Visual Calculator Tutorial 1. Copy all files to another working diskette with your operating system or to a single directory on your hard disk. 2. Type VCYou will get the beginning screen containing the vari- able boxes and the help box at the top. The center of the screen contains the transcript box, and at the bottom you will find the Input box. 3. Type A = 123.45 You will find that the value is displayed in the top box and the value will also be displayed at the left of the input equation in the transcript box. 4. Type B = SQRT(A) You will find the square root of A displayed in both places next to the variable B. You may have noticed that the system doesn't care if you use upper or lower case, it forces it to upper case. You now have defined some values for the variables A and B. 5. Type D = 1.23*SIN(SQRT(1.2345 + B*B/A)) Spaces between variables don't matter and you can put them in where you desire to make it look nice. If you get an error message, simply use the left and right cursor keys along with the delete key to fix up the error and hit the return again. You don't even have to be at the end of the line to hit the return. 6. Hit the F6 key then The F6 requests a file to be read in and if you don't specify a filename, it reads in the file named "HELP". This would be a good place to store a list of your other files in the same manner as this file. 7. Hit the F6 key then type AMORT This reads in the file named "AMORT" and calculates each line as it reads it in. Notice that it also changed the names of the variables that it uses to make them more meaningful to you. 8. Type PRINC = 30000 This changes the amount of the loan. We would like to recalculate the payment which we will in the next few steps. 9. Move the arrow up to the line that starts "PMNT=..." by using the up and down arrow keys. When the arrow is point- ing at the line in question,... 10. Hit the F9 key. This moves the line pointed at, by the little arrow, into the input box where it can be modified or used again as is. 11. Hit the key. This will recalculate the payment based on the new principal and the old interest rates and time of repay- ment. These could also be changed and the payment recalculated. 12. Make sure your printer is ready and hit the F3 key. This will cause a "Print on" message to be printed on your printer and a little "Print" message to be displayed in the upper right of your screen. All equations and the results will be printed for a hardcopy of your calculating session. 13. Hit the F6 key again You will get another prompt for a file name. 14. Type PAYMENT This file will be read in that will give you the results of your mortgage after the first payment. The results will also be printed out. 15. Hit the F6 key again and The last file read in will be reused again and the result of making the second payment will be displayed on the moni- tor and the printer. 16. Repeat step 15 three or four times. 17. Hit the F1 key. A help screen will appear describing the various math functions available. They can be nested to whatever level you desire. 18. Hit the F2 key. A help screen will appear with a very brief description of the system functions available. 19. Hit the "Home" key. You will be immediately transported to the very top of the transcript where the welcome message was originally seen. The Pgup, Pgdn, Home, and End keys will get you through the transcript window very quickly. 20. Move the little arrow to the line that starts "# A-PRINC", and hit the F4 key once. You will see that the asterisk appears in front of the line. This will "mark" the line. Continuing to hit the F4 key will toggle the asterisk on and off. 21. Move the arrow to the line that starts "# E-EQUITY" and mark this line too. 22. Hit the F5 key The system is now prompting you for a file name to output to. 23. Type STUFF This is simply a filename. Any valid filename could be used. All lines in the transcript box that are "marked" will be output to the file "STUFF". 24. Hit the F6 key and type STUFF All of the lines that were just output will be read in and all calculations will be done. 25. Hit the F3 key if the printer is still on. 26. Hit the F6 key and The file will be read in again without printing. 27. Hit the F10 key and answer the prompt with Y to end the session. 28. Type VC again to restart the program. 29. Hit the F6 key, type TEST A file with 50 lines will be read in and all calcu- lations performed as an example of the kinds of equations that can be evaluated. 30. Type the following; # I-D J-O K-H L-X This tells the system that we want the variable "I" to print out in Decimal notation, the variable "J" to print out in Octal notation, and "K" and "L" to print out in HeXadecimal notation. (Note - the # must be in the first column.) 31. Type I = 12345 The variable I will be displayed in all three notations in the top box and in decimal notation in the transcript box. 32. Type J = 12345 The variable J will be displayed in Octal notation in the transcript box and on the printer if it is turned on and ready. 33. Type K = 12345 The variable K will be displayed in Hex notation in the transcript box. 34. Type I = 012345 The value of I is read in as an octal value due to the leading zero, but is still displayed as a decimal value. 35. Type J = 0X12345 The value of J is read in as a hexadecimal value due to the leading 0X. 36. Type M = 0XFFFF The variable M is read in as Hexadecimal and displayed in all three formats in the top box, but as decimal in the transcript box. The default display for the integers is decimal. 37. Type I = SQRT(48) The square root is calculated using 15 significant digits and the result is truncated to the next lower value. All calculations are done this way and the result is truncated to the integer value before display. 38. Type A = FACT(170)/FACT(169) - 170 The very small result will indicate to you a measure of the accuracy of calculations. It may not be apparent to you that we are using a factorial function. Calculate the value of FACT(170) to get an idea of the dynamic range available with this system. 39. Hit the F10 key and answer the prompt with Y. 40. Restart the program and try some of your favorite math exercises. Additional Comments 1. Files on the distribution disk. VC.DOC - The file you are reading. VC.EXE - The executable file for the Visual Calculator. HELP - The users index of files. AMORT - The loan amortization equations. PAYMENT - The monthly payment calculations. TEST - A group of 50 "nonsense" equations. 2. Inputting equations. All equations are typed into the input box in a normal mathematical expression. Only single valued expressions can be evaluated, no simultaneous equations can be solved with this system. To raise "A" to the power of "B", use; C = EXP(B*LOG(A)) $ any variables can be used A dollar sign anywhere in a line renders the remainder of that line as a comment only. Nesting is allowable to any depth but the entire expres- sion must fit in the input window. Longer expressions must be broken down into smaller statements. The variables "I" through "J" can be mixed in with the variables "A" through "F" in any manner. The "I" variables are truncated after evaluation so can only be used to store integer values, but that would be acceptable in many cases, such as the original value of the loan in the above example. 3. Naming variables In order to make the equations easier to read, the names of the variables "A" through "F" can be changed to any names you like with up to 6 characters. The first must be alphabetic and the rest can be alphabetic or numeric. To change the names, use the # sign in the first column of the statement and any order of variable name groups. A variable group is composed of a variable name "A" through "F", then a minus sign, and finally the new name with no blanks any- where in the group. Any number of blanks can be used between the groups, and you can put as many as you like on one input line, and additional groups on other lines. Intermixed with the above, or placed on their own input line, you can put as many "base" groups as you like for the variables "I" through "N". A base group consists of the variable name, a minus sign, and one of the letters, "D", "O", "H", or "X". If, after naming the variables, you wish to rename them to something else, the original names are used for the new name changes. Thus if "A" were named "PLACE" and you wished to rename it to "WHERE" the proper method would be to use "# A-WHERE". 4. Limitations This version of the Visual Calculator has a limit of approximately 800 lines in the transcript box. That should be enough for most applications. If you need more, I would suggest you write the program in a high level language. The limit of numbers is about ten to the plus or minus power of 308. Of course both positive and negative numbers can be used everywhere. The limit for the "I" variables is about 16 million, and can only be zero or positive. The exact number in 2 to the 24th power minus 1. It is the number displayed in the variable "N" when you load the system. The biggest limitation of the system is the limit of your own creativity. It is up to you to use it in a productive manner or simply to allow it to collect dust like so many of your other programs. I might add that I also have many dust collectors that I have failed to learn to use.
/* *************************************************************** */ /* This program reads a series of words from the command line, */ /* and displays all but the last on the monitor. The last is a */ /* series of characters which are used as input comparisons. One */ /* character is read from the keyboard. If it is one of the */ /* characters in the comparison list, its number is returned to */ /* DOS as the errorlevel command. If the character does not exist */ /* in the list, a zero is returned. Example follows; */ /* */ /* WHATNEXT What model do you want? ALR%3T */ /* */ /* What model do you want? <---- displayed on monitor */ /* If key a or A is hit, errorlevel 1 is returned. */ /* If key l or L is hit, errorlevel 2 is returned. */ /* If key r or R is hit, errorlevel 3 is returned. */ /* If key % is hit, errorlevel 4 is returned. */ /* If key 3 is hit, errorlevel 5 is returned. */ /* If key t or T is hit, errorlevel 6 is returned. */ /* If any other key is hit, errorlevel 0 is returned. */ /* */ /* The question must be on one line. */ /* Up to nine different keys can be used. */ /* The errorlevel can be interpreted in a batchfile. */ /* *************************************************************** */ #include "stdio.h" #include "ctype.h" #include "conio.h" #include "process.h" main(int number,char *name[]) { int index; /* a counter and incrementing variable */ int c; /* the character read in for comparison */ int code; /* the resulting errorlevel returned to */ char next_char; /* used for the comparison loop */ char *point; /* a dummy pointer used for convenience */ /* At least one group must be used for this */ /* filename, and one group used for the */ /* required fields, so less than three allows */ /* for no question. */ if (number < 3) { printf("No question given on command line\n"); exit(0); } /* print out words 2 to n-1, the question */ number--; for(index = 1;index < number;index++) { printf("%s ",name[index]); } /* get the users response and make it uppercase */ c = getch(); printf("%c\n",c); if (islower(c)) c = toupper(c); point = name[number];/* point to the last pointer on the inputs */ code = 0; index = 0; do { /* search across allowed responses in last word */ next_char = *(point + index); if (islower(next_char)) next_char = toupper(next_char); /* make it uppercase */ if(next_char == c) /* if a match is found */ code = index + 1; /* save the number of the match */ index++; } while (*(point + index)); /* until NULL terminator found */ exit(code); /* return the errorcode to the system */ }
/******************************************************************/ /* This is an example program to illustrate how to; */ /* 1. Get the time and date from DOS */ /* 2. Set the cursor to any position on the screen */ /* 3. Read characters from the keyboard and display their codes */ /* 4. How to scroll a window up on the monitor */ /* 5. Format a program for ease of reading and understanding */ /* 6. How to do proper prototyping */ /******************************************************************/ void draw_box(void); void disp_char(int inchar); void get_time(int *hour,int *minute,int *second); void disp_time_date(void); void pos_cursor(char row,char column); void scroll_window(void); #include "stdio.h" #include "dos.h" #include "conio.h" int main() { int hour, minute, sec, old_sec; int character; draw_box(); /* draw the boxes around the fields */ old_sec = 0; /* this variable stores the old time so we can look for a change */ do { if (kbhit()) { /* has a key been hit? */ character = getch(); /* read it in */ disp_char(character); /* display it */ } get_time(&hour,&minute,&sec); /* get the time of day */ if (sec != old_sec) { /* if it has changed, */ disp_time_date(); /* update the display */ old_sec = sec; /* save new time */ } } while (character != 'Q'); /* Quit when a Q is found */ pos_cursor(0,0); /* put cursor at top of screen */ } /* **************************************************** drawbox */ /* This routine draws a box on the screen. The keys hit, and */ /* the time and date are displayed in these boxes. There is */ /* nothing special about these boxes, they are simply output */ /* using the printf function. */ /* ************************************************************ */ void draw_box(void) { int index; char line[81]; for (index = 0;index < 80;index++) /* three blank rows */ line[index] = ' '; line[80] = NULL; /* end of string */ for (index = 0;index < 3;index++) printf("%s",line); line[8] = 201; /* draw top line of box */ for (index = 9;index < 70;index++) line[index] = 205; line[70] = 187; printf("%s",line); line[8] = 186; /* draw sides of large box */ for (index = 9;index < 70;index++) line[index] = ' '; line[70] = 186; for (index = 0;index < 15;index++) printf("%s",line); line[8] = 204; /* draw line between boxes */ for (index = 9;index < 70;index++) line[index] = 205; line[70] = 185; printf("%s",line); line[8] = 186; /* sides for time/date box */ for (index = 9;index < 70;index++) line[index] = ' '; line[70] = 186; printf("%s",line); line[8] = 200; /* bottom line of the box */ for (index = 9;index < 70;index++) line[index] = 205; line[70] = 188; printf("%s",line); for (index = 0;index < 80;index++) /* three blank rows */ line[index] = ' '; for (index = 0;index < 3;index++) printf("%s",line); } /* ************************************************** disp_char */ /* This routine displays the characters hit on the monitor. If */ /* the first character is a zero, a special character has been */ /* hit, and the zero is displayed. The next character is read, */ /* and it is displayed on the monitor. */ /* ************************************************************ */ void disp_char(int inchar) { scroll_window(); pos_cursor(17,15); /* position of message on screen */ if(inchar == 0) { printf(" 00 "); /* a special character was hit */ inchar = getch(); /* get the next part of it */ switch (inchar) { case 59 : case 60 : case 61 : case 62 : case 63 : /* these are the function keys */ case 64 : case 65 : case 66 : case 67 : case 68 : printf("%4d Function key F%d\n",inchar,inchar-58); break; case 94 : case 95 : case 96 : case 97 : case 98 : /* these are the ctrl-function keys */ case 99 : case 100 : case 101 : case 102 : case 103 : printf("%4d Function key Ctrl-F%d\n",inchar, inchar-93); break; case 84 : case 85 : case 86 : case 87 : /* these are the upper-function keys */ case 88 : case 89 : case 90 : case 91 : case 92 : case 93 : printf("%4d Function key Upper-F%d\n",inchar, inchar-83); break; case 104 : case 105 : case 106 : case 107 : case 108 : /* these are the alt-function keys */ case 109 : case 110 : case 111 : case 112 : case 113 : printf("%4d Function key Alt-F%d\n",inchar, inchar-103); break; default : printf("%4d Special key hit\n",inchar); } } else /* a regular character was hit */ printf(" %4d (%c) Character Hit.\n",inchar,inchar); pos_cursor(25,1); /* hide the cursor on the 26th line */ } /* *************************************************** get_time */ /* This routine calls the DOS function call for time of day. It */ /* returns the time of day to the calling program in the three */ /* pointers used in the call. */ /* ************************************************************ */ void get_time(int *hour,int *minute,int *second) { union REGS inregs; union REGS outregs; inregs.h.ah = 44; /* Hex 2C - Get current time */ int86(0x21,&inregs,&outregs); *hour = outregs.h.ch; *minute = outregs.h.cl; *second = outregs.h.dh; } /* ********************************************* disp_time_date */ /* This routine displays the time and date on the monitor in a */ /* fixed position. It gets the time from the get_time function, */ /* and gets the date from its own built in DOS call. Good */ /* programming practice would move the date to another function */ /* but this is an illustrative example to display methods of */ /* doing things. This routine also calls the cursor positioning */ /* function to put the time and date where we want them. */ /* ************************************************************ */ void disp_time_date(void) { int hour, minute, second; union REGS inregs; union REGS outregs; pos_cursor(19,19); /* position the cursor for date and time */ inregs.h.ah = 42; /* hex 2A - What is the date? */ int86(0x21,&inregs,&outregs); /* interrupt 21 */ printf("Date = %2d/%2d/%2d ", outregs.h.dh, /* month - 1 to 12 */ outregs.h.dl, /* day - 1 to 31 */ outregs.x.cx); /* year - 1980 to 2099 */ get_time(&hour, &minute, &second); printf("Time = %2d:%2d:%2d\n",hour, minute, second); pos_cursor(25,1); /* hide the cursor on the 26th line */ } /* ************************************************* pos_cursor */ /* This routine positions the cursor at the requested row and */ /* column. The upper left corner is row 0 and column 0 */ /* ************************************************************ */ void pos_cursor(char row,char column) { union REGS inregs; union REGS outregs; inregs.h.ah = 2; /* service 2 - position the cursor */ inregs.h.dh = row; inregs.h.dl = column; inregs.h.bh = 0; int86(0x10,&inregs,&outregs); /* interrupt 10 */ } /* ********************************************** scroll_window */ /* This routine scrolls all of the material in the key hit */ /* window up one space leaving room for another entry. */ /* ************************************************************ */ void scroll_window(void) { union REGS inregs; union REGS outregs; inregs.h.ah = 6; /* service 6 - scroll window */ inregs.h.al = 1; /* number of lines to scroll */ inregs.h.ch = 3; /* top row of window */ inregs.h.cl = 9; /* left column of window */ inregs.h.dh = 17; /* bottom row of window */ inregs.h.dl = 69; /* right column of window */ inregs.h.bh = 7; /* attribute of blank line */ int86(0x10,&inregs,&outregs); /* interrupt 10 */ }
/* *************************************************************** */ /* This program will read in any text file and list it on the */ /* monitor with line numbers and with page numbers. */ /* *************************************************************** */ #include "stdio.h" /* standard I/O header file */ #include "io.h" /* file I/O prototypes */ void open_file(int no,char *name); void open_print_file(void); void print_a_line(void); void top_of_page(void); #define MAXCHARS 255 /* maximum size of a line */ FILE *file_point; /* pointer to file to be read */ FILE *print_file_point; /* pointer to pronter */ char oneline[256]; /* input string buffer area */ main(number,name) int number; /* number of arguments on command line */ char *name[]; /* arguments on the command line */ { char *c; /* variable to indicate end of file */ char *point; point = name[1]; open_file(number,point); /* open the file to read and print */ open_print_file(); do { c = fgets(oneline,MAXCHARS,file_point); /* read one line */ if (c != NULL) print_a_line(); /* print the line */ } while (c != NULL); /* continue until EOF */ top_of_page(); /* move paper to top of page */ fclose(file_point); /* close read file */ fclose(print_file_point); /* close printer file */ }